/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package analysis;

import java.lang.reflect.Method;
import java.util.Stack;
import java.util.Vector;
//import javax.tools.JavaFileManager.Location;
import main.ServerScripts;
import node.*;
import org.cojen.classfile.Label;
import org.cojen.classfile.Opcode;
import org.cojen.classfile.TypeDesc;
/**
 *
 * @author zgredzik
 */
public class ClassGenerator extends DepthFirstAdapter {
    boolean m_bGlobal;
    TypeDesc m_objIdentType;
    Stack m_objIdentName;
    Stack m_objIdentSize;
    Vector m_objArgTypeList;
    Stack m_objBinops;
    String m_strRelop;
    Stack m_objLabels;
    
    /**
     * constructor
     * @param A_bGlobal 
     */
    public ClassGenerator(/*boolean A_bGlobal*/)
    {
        //m_bGlobal = A_bGlobal;
        m_objIdentName = new Stack();
        m_objIdentSize = new Stack();
        m_objArgTypeList = new Vector();
        m_objBinops = new Stack();
        m_strRelop = "";
        m_objLabels = new Stack();
    }
    
    // setting the type
    @Override
    public void caseAVoidTypeSpecifier(AVoidTypeSpecifier node)
    {
        m_objIdentType = TypeDesc.VOID;
    }
    
    @Override
    public void caseACharTypeSpecifier(ACharTypeSpecifier node)
    {
        m_objIdentType = TypeDesc.CHAR;
    }
    
    @Override
    public void caseASignedIntTypeSpecifier(ASignedIntTypeSpecifier node)
    {
        //m_objIdentType = TypeDesc.INT;
        m_objIdentType = TypeDesc.DOUBLE;
    }
    
    @Override
    public void caseADoubleTypeSpecifier(ADoubleTypeSpecifier node)
    {
        m_objIdentType = TypeDesc.DOUBLE;
    }
    
    @Override
    public void caseAStringTypeSpecifier(AStringTypeSpecifier node)
    {
        m_objIdentType = TypeDesc.STRING;
    }
    
    // setting the identifier name
    @Override
    public void caseAIdentifierDirectDeclarator(AIdentifierDirectDeclarator node)
    {
        TIdentifier identifier = node.getIdentifier();
        m_objIdentName.push(identifier.getText());
        m_objIdentSize.push(0);
    }
    @Override
    public void caseAIdentifierArrayDeclarator(AIdentifierArrayDeclarator node)
    {
        TIdentifier identifier = node.getIdentifier();
        //m_objIdentName.push(identifier.getText());
        m_objIdentSize.push(Integer.parseInt(node.getIntegerConstant().getText()));
    }
    @Override
    public void caseAIdentifierDirectFunctionDeclarator(AIdentifierDirectFunctionDeclarator node)
    {
        TIdentifier identifier = node.getIdentifier();
        //m_objIdentName.push(identifier.getText());
    }
    
    // adding a variable
    @Override
    public void outAVariableDeclaration(AVariableDeclaration node)
    {
        while(!m_objIdentName.empty())
            ServerScripts.AddVariable(m_objIdentType, (String)m_objIdentName.pop());
    }
    
    // setting variable's value
    @Override
    public void caseAIdentifierVarname(AIdentifierVarname node)
    {
        TIdentifier identifier = node.getIdentifier();
        m_objIdentName.push(identifier.getText());
    }
    
    // puttin stuff on ze stack
    @Override
    public void caseAFloatingConstant(AFloatingConstant node)
    {
        TFloatingConstant value = node.getFloatingConstant();
        ServerScripts.GetCB().loadConstant(Double.parseDouble(value.getText()));
        System.out.println("caseAFloatingConstant: " + Double.parseDouble(value.getText()));
    }
    
    @Override
    public void caseAStringConstant(AStringConstant node)
    {
        TStringLitteral value = node.getStringLitteral();
        ServerScripts.GetCB().loadConstant(value.getText().substring(1, value.getText().length()-1));
        System.out.println("caseAStringConstant: " + value.getText().substring(1, value.getText().length()-1));
    }
    
    @Override
    public void caseAIntegerConstant(AIntegerConstant node)
    {
        TIntegerConstant value = node.getIntegerConstant();
        ServerScripts.GetCB().loadConstant(Double.parseDouble(value.getText()));
        System.out.println("caseAIntegerConstant: " + Double.parseDouble(value.getText()));
        //ServerScripts.GetCB().loadConstant(Integer.parseInt(value.getText()));
        //System.out.println("caseAIntegerConstant: " + Integer.parseInt(value.getText()));
    }
    
    @Override
    public void caseACharacterConstant(ACharacterConstant node)
    {
        TCharacterConstant value = node.getCharacterConstant();
        ServerScripts.GetCB().loadConstant(value.getText().charAt(1));
        System.out.println("caseACharacterConstant: " + value.getText().charAt(1));
    }
    
    @Override
    public void caseAIdentifierValue(AIdentifierValue node)
    {
        TIdentifier identifier = node.getIdentifier();
        ServerScripts.LoadLocal(identifier.getText());
    }
    
    // modify expression
    @Override
    public void outADirectModifyExpression(ADirectModifyExpression node)
    {
        ServerScripts.StoreVariable((String)m_objIdentName.pop());
    }
    
    // call expression
    @Override
    public void outACallExpression(ACallExpression node)
    {
        TIdentifier identifier = node.getIdentifier();
        ServerScripts.InvokeStatic(identifier.getText());
    }
    
    // relational operators
    /*@Override
    public void case()
    {
        
    }*/
    
    // binary operators
    @Override
    public void caseAStarBinop(AStarBinop node)
    {
        m_objBinops.push('*');
    }
    
    @Override
    public void caseADivBinop(ADivBinop node)
    {
        m_objBinops.push('/');
    }
    
    @Override
    public void caseAPlusBinop(APlusBinop node)
    {
        m_objBinops.push('+');
    }
    
    @Override
    public void caseAMinusBinop(AMinusBinop node)
    {
        m_objBinops.push('-');
    }
    
    @Override
    public void outABinaryExpression(ABinaryExpression node)
    {
        char c = (Character)m_objBinops.pop();
        byte opcode = Opcode.DADD;
        System.out.println("outAConstantBinaryExpression: " + c);
        switch(c)
        {
            case '*': opcode = Opcode.DMUL;
                break;
            case '/': opcode = Opcode.DDIV;
                break;
            case '+': opcode = Opcode.DADD;
                break;
            case '-': opcode = Opcode.DSUB;
                break;
        }
        ServerScripts.GetCB().math(opcode);
    }
    
    // conditions
    /*@Override
    public void caseAExclMarkUnop(AExclMarkUnop node)
    {
        m_strRelop = "!";
    }
    @Override
    public void caseAPlusUnop(APlusUnop node)
    {
        m_strRelop = "+";
    }
    @Override
    public void caseAMinusUnop(AMinusUnop node)
    {
        m_strRelop = "-";
    }*/
    @Override
    public void caseAEqRelop(AEqRelop node)
    {
        m_strRelop = "!=";
    }
    @Override
    public void caseANeqRelop(ANeqRelop node)
    {
        m_strRelop = "==";
    }
    @Override
    public void caseALtRelop(ALtRelop node)
    {
        m_strRelop = ">=";
    }
    @Override
    public void caseALteqRelop(ALteqRelop node)
    {
        m_strRelop = ">";
    }
    @Override
    public void caseAGtRelop(AGtRelop node)
    {
        m_strRelop = "<=";
    }
    @Override
    public void caseAGteqRelop(AGteqRelop node)
    {
        m_strRelop = "<";
    }
    
    @Override
    public void outAConditionalExpression(AConditionalExpression node)
    {
        Label label = (Label)m_objLabels.push(ServerScripts.GetCB().createLabel());
        ServerScripts.GetCB().ifComparisonBranch(label, m_strRelop, TypeDesc.DOUBLE);
        //ServerScripts.GetCB().branch(label);
        System.out.println("outAConditionalExpression: " + m_strRelop);
    }
    
    @Override
    public void outAIfStatement(AIfStatement node)
    {
        System.out.println("outAIfStatement ----------------");
        Label label = (Label)m_objLabels.pop();
        label.setLocation();
    }
    
    // looping
    @Override
    public void inAWhileStatement(AWhileStatement node)
    {
        System.out.println("inAWhileStatement ----------------");
        m_objLabels.push(ServerScripts.GetCB().createLabel().setLocation());
    }
    @Override
    public void outAWhileStatement(AWhileStatement node)
    {
        System.out.println("outAWhileStatement ----------------");
        Label label = (Label)m_objLabels.pop();
        Label label2 = (Label)m_objLabels.pop();
        ServerScripts.GetCB().branch(label2);
        label.setLocation();
    }
}
